From: Keir Fraser Date: Wed, 14 May 2008 12:50:46 +0000 (+0100) Subject: Get ACPI Px from dom0 and choose Px controller X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~14215^2~3 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https://%22%22/%22http:/www.example.com/cgi/%22https:/%22%22?a=commitdiff_plain;h=2fa7bee0a09f465f1a96e52512a4a7749328d33e;p=xen.git Get ACPI Px from dom0 and choose Px controller Add platform op hypercall case to get ACPI Px info from dom0. Chose Px controller from dom0 (cpufreq=dom0-kernel) or hypervisor (cpufreq=xen). Signed-off-by: Liu Jinsong --- diff --git a/xen/arch/x86/acpi/Makefile b/xen/arch/x86/acpi/Makefile index 6233479e30..1a82f5d75c 100644 --- a/xen/arch/x86/acpi/Makefile +++ b/xen/arch/x86/acpi/Makefile @@ -1,2 +1,4 @@ +subdir-y += cpufreq + obj-y += boot.o obj-y += power.o suspend.o wakeup_prot.o cpu_idle.o diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c index 2dc5fa7256..f6a80cf3b1 100644 --- a/xen/arch/x86/acpi/cpu_idle.c +++ b/xen/arch/x86/acpi/cpu_idle.c @@ -834,7 +834,7 @@ static int set_cx(struct acpi_processor_power *acpi_power, return 0; } -static int get_cpu_id(u8 acpi_id) +int get_cpu_id(u8 acpi_id) { int i; u8 apic_id; diff --git a/xen/arch/x86/acpi/cpufreq/Makefile b/xen/arch/x86/acpi/cpufreq/Makefile new file mode 100644 index 0000000000..9ffb2d4917 --- /dev/null +++ b/xen/arch/x86/acpi/cpufreq/Makefile @@ -0,0 +1 @@ +obj-y += cpufreq.o diff --git a/xen/arch/x86/acpi/cpufreq/cpufreq.c b/xen/arch/x86/acpi/cpufreq/cpufreq.c new file mode 100644 index 0000000000..cdf43c8acf --- /dev/null +++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c @@ -0,0 +1,52 @@ +/* + * cpufreq.c - ACPI Processor P-States Driver ($Revision: 1.4 $) + * + * Copyright (C) 2001, 2002 Andy Grover + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (C) 2002 - 2004 Dominik Brodowski + * Copyright (C) 2006 Denis Sadykov + * + * Feb 2008 - Liu Jinsong + * porting acpi-cpufreq.c from Linux 2.6.23 to Xen hypervisor + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct processor_pminfo processor_pminfo[NR_CPUS]; + +int acpi_cpufreq_init(void) +{ + return 0; +} diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 677e4997df..5538eb3149 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include "cpu/mtrr/mtrr.h" @@ -346,9 +347,68 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) switch ( op->u.set_pminfo.type ) { case XEN_PM_PX: - ret = -EINVAL; + { + static int cpu_count = 0; + struct xenpf_set_processor_pminfo *xenpmpt = &op->u.set_pminfo; + struct xen_processor_performance *xenpxpt = &op->u.set_pminfo.perf; + int cpuid = get_cpu_id(xenpmpt->id); + struct processor_pminfo *pmpt; + struct processor_performance *pxpt; + + if ( cpuid < 0 ) + { + ret = -EINVAL; + break; + } + pmpt = &processor_pminfo[cpuid]; + pxpt = &processor_pminfo[cpuid].perf; + pmpt->acpi_id = xenpmpt->id; + pmpt->id = cpuid; + + if ( xenpxpt->flags & XEN_PX_PCT ) + { + memcpy ((void *)&pxpt->control_register, + (void *)&xenpxpt->control_register, + sizeof(struct xen_pct_register)); + memcpy ((void *)&pxpt->status_register, + (void *)&xenpxpt->status_register, + sizeof(struct xen_pct_register)); + } + if ( xenpxpt->flags & XEN_PX_PSS ) + { + if ( !(pxpt->states = xmalloc_array(struct xen_processor_px, + xenpxpt->state_count)) ) + { + ret = -ENOMEM; + break; + } + if ( copy_from_compat(pxpt->states, xenpxpt->states, + xenpxpt->state_count) ) + { + xfree(pxpt->states); + ret = -EFAULT; + break; + } + pxpt->state_count = xenpxpt->state_count; + } + if ( xenpxpt->flags & XEN_PX_PSD ) + { + pxpt->shared_type = xenpxpt->shared_type; + memcpy ((void *)&pxpt->domain_info, + (void *)&xenpxpt->domain_info, + sizeof(struct xen_psd_package)); + } + if ( xenpxpt->flags & XEN_PX_PPC ) + pxpt->ppc = xenpxpt->ppc; + + if ( xenpxpt->flags == ( XEN_PX_PCT | XEN_PX_PSS | + XEN_PX_PSD | XEN_PX_PPC ) ) + cpu_count++; + if ( cpu_count == num_online_cpus() ) + ret = acpi_cpufreq_init(); break; - + } + case XEN_PM_CX: ret = set_cx_pminfo(op->u.set_pminfo.id, &op->u.set_pminfo.power); break; diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index add264d914..03b5611987 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -95,9 +95,9 @@ extern int skip_ioapic_setup; boolean_param("noapic", skip_ioapic_setup); /* **** Linux config option: propagated to domain0. */ -/* xen_processor_pm: xen control cstate. */ -static int xen_processor_pm; -boolean_param("xen_processor_pm", xen_processor_pm); +/* xen_cpuidle: xen control cstate. */ +static int xen_cpuidle; +boolean_param("cpuidle", xen_cpuidle); int early_boot = 1; @@ -988,6 +988,7 @@ void __init __start_xen(unsigned long mbi_p) if ( (cmdline != NULL) || (kextra != NULL) ) { static char dom0_cmdline[MAX_GUEST_CMDLINE]; + char xen_pm_param[32]; cmdline = cmdline_cook(cmdline); safe_strcpy(dom0_cmdline, cmdline); @@ -1012,8 +1013,14 @@ void __init __start_xen(unsigned long mbi_p) safe_strcat(dom0_cmdline, " acpi="); safe_strcat(dom0_cmdline, acpi_param); } - if ( xen_processor_pm && !strstr(dom0_cmdline, "xen_processor_pmbits=") ) - safe_strcat(dom0_cmdline, " xen_processor_pmbits=1"); + if ( xen_cpuidle ) + xen_processor_pmbits |= XEN_PROCESSOR_PM_CX; + + snprintf(xen_pm_param, sizeof(xen_pm_param), + " xen_processor_pmbits=%d", xen_processor_pmbits); + + if ( !strstr(dom0_cmdline, "xen_processor_pmbits=") ) + safe_strcat(dom0_cmdline, xen_pm_param); cmdline = dom0_cmdline; } diff --git a/xen/arch/x86/x86_64/platform_hypercall.c b/xen/arch/x86/x86_64/platform_hypercall.c index 534c7be27f..037ab4f4af 100644 --- a/xen/arch/x86/x86_64/platform_hypercall.c +++ b/xen/arch/x86/x86_64/platform_hypercall.c @@ -11,6 +11,12 @@ DEFINE_XEN_GUEST_HANDLE(compat_platform_op_t); #define xen_platform_op_t compat_platform_op_t #define do_platform_op(x) compat_platform_op(_##x) +#define xen_processor_px compat_processor_px +#define xen_processor_px_t compat_processor_px_t +#define xen_processor_performance compat_processor_performance +#define xen_processor_performance_t compat_processor_performance_t +#define xenpf_set_processor_pminfo compat_pf_set_processor_pminfo + #define xen_processor_power compat_processor_power #define xen_processor_power_t compat_processor_power_t #define set_cx_pminfo compat_set_cx_pminfo diff --git a/xen/common/domain.c b/xen/common/domain.c index c74fb07c0e..687101d8e9 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -30,6 +30,10 @@ #include #include +/* Linux config option: propageted to domain0 */ +/* xen_processor_pmbits: xen control Cx, Px, ... */ +unsigned int xen_processor_pmbits = 0; + /* opt_dom0_vcpus_pin: If true, dom0 VCPUs are pinned. */ static unsigned int opt_dom0_vcpus_pin; boolean_param("dom0_vcpus_pin", opt_dom0_vcpus_pin); @@ -39,9 +43,15 @@ static void __init setup_cpufreq_option(char *str) { if ( !strcmp(str, "dom0-kernel") ) { + xen_processor_pmbits &= ~XEN_PROCESSOR_PM_PX; cpufreq_controller = FREQCTL_dom0_kernel; opt_dom0_vcpus_pin = 1; } + else if ( !strcmp(str, "xen") ) + { + xen_processor_pmbits |= XEN_PROCESSOR_PM_PX; + cpufreq_controller = FREQCTL_none; + } } custom_param("cpufreq", setup_cpufreq_option); diff --git a/xen/include/acpi/cpufreq/processor_perf.h b/xen/include/acpi/cpufreq/processor_perf.h new file mode 100644 index 0000000000..27add2a77f --- /dev/null +++ b/xen/include/acpi/cpufreq/processor_perf.h @@ -0,0 +1,30 @@ +#ifndef __XEN_PROCESSOR_PM_H__ +#define __XEN_PROCESSOR_PM_H__ + +#include + +int get_cpu_id(u8); +int acpi_cpufreq_init(void); + +struct processor_performance { + uint32_t state; + uint32_t ppc; + struct xen_pct_register control_register; + struct xen_pct_register status_register; + uint32_t state_count; + struct xen_processor_px *states; + struct xen_psd_package domain_info; + cpumask_t shared_cpu_map; + uint32_t shared_type; +}; + +struct processor_pminfo { + uint32_t acpi_id; + uint32_t id; + uint32_t flag; + struct processor_performance perf; +}; + +extern struct processor_pminfo processor_pminfo[NR_CPUS]; + +#endif /* __XEN_PROCESSOR_PM_H__ */ diff --git a/xen/include/public/platform.h b/xen/include/public/platform.h index 9e839ee73e..3f4fbfb661 100644 --- a/xen/include/public/platform.h +++ b/xen/include/public/platform.h @@ -211,6 +211,12 @@ DEFINE_XEN_GUEST_HANDLE(xenpf_getidletime_t); #define XEN_PM_PX 1 #define XEN_PM_TX 2 +/* Px sub info type */ +#define XEN_PX_PCT 1 +#define XEN_PX_PSS 2 +#define XEN_PX_PPC 4 +#define XEN_PX_PSD 8 + struct xen_power_register { uint32_t space_id; uint32_t bit_width; @@ -252,12 +258,55 @@ struct xen_processor_power { XEN_GUEST_HANDLE(xen_processor_cx_t) states; /* supported c states */ }; +struct xen_pct_register { + uint8_t descriptor; + uint16_t length; + uint8_t space_id; + uint8_t bit_width; + uint8_t bit_offset; + uint8_t reserved; + uint64_t address; +}; + +struct xen_processor_px { + uint64_t core_frequency; /* megahertz */ + uint64_t power; /* milliWatts */ + uint64_t transition_latency; /* microseconds */ + uint64_t bus_master_latency; /* microseconds */ + uint64_t control; /* control value */ + uint64_t status; /* success indicator */ +}; +typedef struct xen_processor_px xen_processor_px_t; +DEFINE_XEN_GUEST_HANDLE(xen_processor_px_t); + +struct xen_psd_package { + uint64_t num_entries; + uint64_t revision; + uint64_t domain; + uint64_t coord_type; + uint64_t num_processors; +}; + +struct xen_processor_performance { + uint32_t flags; /* flag for Px sub info type */ + uint32_t ppc; /* Platform limitation on freq usage */ + struct xen_pct_register control_register; + struct xen_pct_register status_register; + uint32_t state_count; /* total available performance states */ + XEN_GUEST_HANDLE(xen_processor_px_t) states; + struct xen_psd_package domain_info; + uint32_t shared_type; /* coordination type of this processor */ +}; +typedef struct xen_processor_performance xen_processor_performance_t; +DEFINE_XEN_GUEST_HANDLE(xen_processor_performance_t); + struct xenpf_set_processor_pminfo { /* IN variables */ uint32_t id; /* ACPI CPU ID */ - uint32_t type; /* {XEN_PM_CX, ...} */ + uint32_t type; /* {XEN_PM_CX, XEN_PM_PX} */ union { struct xen_processor_power power;/* Cx: _CST/_CSD */ + struct xen_processor_performance perf; /* Px: _PPC/_PCT/_PSS/_PSD */ }; }; typedef struct xenpf_set_processor_pminfo xenpf_set_processor_pminfo_t; diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h index ff471ab930..2e8e4f979b 100644 --- a/xen/include/xen/domain.h +++ b/xen/include/xen/domain.h @@ -57,4 +57,6 @@ void arch_dump_domain_info(struct domain *d); int arch_vcpu_reset(struct vcpu *v); +extern unsigned int xen_processor_pmbits; + #endif /* __XEN_DOMAIN_H__ */